﻿/// <reference path="jquery.js" />
/// <reference path="../jquery-vsdoc.js" />
/// <reference path="laytpl.js" />
/// <reference path="LiberUI.Base.js" />

if (!window.LiberUI) {
    LiberUI = {};
    var MouseEvent = null;
    var mouseStoper = null;
    LiberUI.IsCheckingMouse = false;
    LiberUI.MouseMoinitor = function (ev) {
        //捕获鼠标事件待后面使用
        MouseEvent = ev || window.event;
    };
    LiberUI.Stopper = function () {
        MouseEvent = null;
        LiberUI.IsCheckingMouse = false;
        document.removeEventListener("mousemove", LiberUI.MouseMoinitor);
        window.clearTimeout(mouseStoper);
    };
    LiberUI.TryGetHotElement = function () {
        if (LiberUI.IsCheckingMouse == false) {
            document.addEventListener("mousemove", LiberUI.MouseMoinitor);
            LiberUI.IsCheckingMouse = true;

            //停止将要执行的停止动作
            if (mouseStoper != null) {
                window.clearTimeout(mouseStoper);
            }
            mouseStoper = setTimeout(LiberUI.Stopper, 10000);  //10秒后停止监听,除非此方法被再次调用
            return null;
        }
        else {
            //TODO:计算鼠标当前停留的元素,考虑不同浏览器的实现方式
            //停止将要执行的停止动作
            if (mouseStoper != null) {
                window.clearTimeout(mouseStoper);
            }
            mouseStoper = setTimeout(LiberUI.Stopper, 10000);  //10秒后停止监听,除非此方法被再次调用
            return MouseEvent == null ? null : $(MouseEvent.toElement);
        }
    };
}

function LController($elm) {
    if (ObjHelper.IsEmpty($elm)) {
        $elm = $("<div>");
    }
    else {
        $elm = $($elm);
        if ($elm.length > 0) {
            $elm = $elm.eq(0);
        }
        else {
            $elm = $("<div>");
        }
    }
    var ins = this;
    var opt = { StyleDisable: "disabled" };
    opt.ShowWay = function (elm) {
        elm.show();
    };
    opt.HideWay = function (elm) {
        elm.hide();
    };

    var data = null;
    this.State = {
        disposed : false,
        enabled : true
    };
    this.Dom = $elm;

    this.on = function (event, fn) {
        if (event == "focus" || event == "click"||event=="dbclick"||event=="blur") {
            event = "LC" + event;
        }
        $elm.on(event, fn);
        return this;
    };
    this.off = function (event, fn) {
        $elm.off(event, fn);
        return this;
    };
    this.vl = function (value) {
        if (value === undefined) {
            return data;
        }
        else {
            var ev = jQuery.Event("valueChanging", {Controller:ins,OldValue:data,NewValue:value});
            this.Dom.trigger(ev);
            if (ev.isDefaultPrevented()) {
                return ins;
            }   
            ev = jQuery.Event("valueChanged", { Controller: ins,OldValue:data, NewValue: value });
            data = value;
            this.Dom.trigger(ev);
            ev = null;
            return ins;
        }
    };
    this.option = function (name, value) {
        /// <summary>
        /// 获取或设置某个选项的值
        /// </summary>
        /// <param name="name" type="string">选项名</param>
        /// <param name="value" type="object">选项值</param>
        if (!name) {
            return opt;
        }
        else if (value==null||value==undefined) {
            return opt[name];
        }
        else {
            opt[name] = value;
            return ins;
        }
    };
    this.dispose = function () {
        if (this.State.disposed == true) {
            return null;
        }
        this.State.disposed = true;
        var ev = $.Event("disposed", { Controller: ins });
        this.Dom.trigger(ev);
        this.Dom.Controller = null;
        this.Dom.remove();
        data = null;
        ins = null;
        ev = null;
        opt = null;
        this.Dom = null;
        this.State = null;
        return null;
    };
    this.editble = false;

    var onDomClick = function (ev) {
        if (ins.State.enabled == false) {
            return ins;
        }
        if (ev && ev.stopPropagation) {
            ev.stopPropagation();
        }
        var nev = $.Event("LCclick", { Controller: ins });
        ins.Dom.trigger(nev);
        return ins;
    };
    var onDomBlur = function (ev) {
        if (ins.State.enabled == false) {
            return ins;
        }
        if (ev && ev.stopPropagation) {
            ev.stopPropagation();
        }
        var nev = $.Event("LCblur", { Controller: ins });
        ins.Dom.trigger(nev);
        return ins;
    };
    var onDomFocus = function (ev) {
        if (ins.State.enabled == false) {
            return ins;
        }
        if (ev && ev.stopPropagation) {
            ev.stopPropagation();
        }
        var nev = $.Event("LCfocus", { Controller: ins });
        ins.Dom.trigger(nev);
        return ins;
    };
    this.Dom.on("click", onDomClick);  //防止冲突，将Dom的Clic转换为自定义的LCclick事件
    this.Dom.on("blur", onDomBlur);
    this.Dom.on("focus", onDomFocus);
    this.Dom.data("Controller", ins);
    return ins;
};

LController.prototype = {
    "update":function(){
        if (this.State.disposed == false) {
            var ev = jQuery.Event("update", { Controller: this });
            this.Dom.trigger(ev);
        }
        return this;
    },
    "addClass": function (cssClass) {
        this.Dom.addClass(cssClass);
        return this;
    },
    "attr":function(name,value){
        return this.Dom.attr(name, value);
    },
    "ID": function (newId) {
        return this.Dom.ID(newId);
    },
    "show": function () {
        var ev = jQuery.Event("shown", { Controller: this });
        this.Dom.trigger(ev);
        if (this.option("ShowWay")) {
            this.option("ShowWay").call(this,this.Dom);
        }
        else {
            this.Dom.fadeIn();
        }
        return this;
    },
    "hide": function () {
        var ev = jQuery.Event("hiden", { Controller: this });
        this.Dom.trigger(ev);
        if (this.option("HideWay")) {
            this.option("HideWay").call(this,this.Dom);
        }
        else {
            this.Dom.fadeOut();
        }
        return this;
    },
    "focus": function () {
        var ev = jQuery.Event("LCfocus", { Controller: this });
        this.Dom.trigger(ev);
        return this;
    },
    "disable" : function () {
        this.State.enabled = false;
        var ev = jQuery.Event("disabled", { Controller: this });
        this.Dom.trigger(ev).addClass("disabled");
        this.update();
        return this;
    },
    "enable" : function () {
        this.State.enabled = true;
        var ev = jQuery.Event("enabled", { Controller: this });
        this.Dom.trigger(ev).removeClass("disabled");
        this.update();
        return this;
    },
}

//#region 按钮
LiberUI.Button = function ($elm) {
    /// <summary>
    /// 创建或转换一个Button控件实例
    /// </summary>
    /// <param name="$elm" type="JQuery Object OR DOM">要转换的DOM元素或选择符</param>
    /// <returns type=""></returns>
    var ins = this;
    LController.call(this, $elm);

    var _update = function (ev) {
        ins.Dom.vl(ins.vl());
        if (ins.State.enabled == true) {
            ins.Dom.removeClass(ins.option('StyleDisable'));
        }
        else {
            ins.Dom.addClass(ins.option('StyleDisable'));
        }
    };

    this.on("update", _update);
    this.on("valueChanged", _update);
    this.on("shown", function () { ins.Dom.show(); });
    this.on("hiden", function () { ins.Dom.hide(); });
    this.constructor = LiberUI.Button;
    return ins;
}
LiberUI.Button.prototype = LController.prototype;
//#endregion

//#region CheckBox
LiberUI.CheckBox = function ($elm) {
    /// <summary>
    /// 创建或转换一个CheckBox控件实例
    /// 可通过直接设置vl为checked、unchecked、partChecked来改变状态
    /// </summary>
    /// <param name="$elm" type="JQuery Object OR DOM">要转换的DOM元素或选择符</param>
    /// <returns type=""></returns>
    var ins = this;
    LController.call(this, $elm);
    this.option("PartCheckble", false);
    ins.Dom.addClass("checkbox");

    var _update = function (ev) {
        var v = ins.vl();
        switch (v) {
            case "checked":
                ins.Dom.removeClass("unchecked");
                break;
            case "unchecked":
                ins.Dom.addClass("unchecked");
                break;
            case "partChecked":
                break;
            default:
                break;
        }
    };
    var onDomClick = function (ev) {
        ev.stopPropagation();
        var v=ins.vl();
        if (v == "checked") {
            ins.vl("unchecked").update();  
        }
        else {
            ins.vl("checked").update();
        }
    };
    ins.vl("checked"); //设置默认值
    this.on("LCclick", onDomClick);
    this.on("update", _update);
    this.on("valueChanged", _update);
    this.constructor = LiberUI.Button;
    return ins;
}
LiberUI.CheckBox.prototype = LController.prototype;
//#endregion

//#region表单
LiberUI.Form = function ($elm) {
    var ins = this;
    LController.call(this, $elm);
    var items = [];
    
    var onItemKeyEnter = function (ev) {
        if (ev.Dom) {
            var i = ev.Dom.attr("frm-index");
            if (i < items.length-1) {
                items[++i].focus().select();
            }
            else {
                //TODO:最后一个元素上的Enter事件
                ins.Submit();
            }
        }
    };
    var onFormFocus = function (ev) {
        if (items.length > 0) {
            items[0].focus().select();
        }
    };
    var onFormDispose = function (ev) {
        for (var i = 0; i < items.length; i++) {
            KeybordHelper.off(items[i], "enter", onItemKeyEnter);
        }
        items = [];
    };

    //扫描其中所有input和contentEditble、textarea、LController，加入到子元素，并控制焦点切换和对象绑定
    ins.Dom.children().each(function () {
        var i = $(this);
        if (i.editble() == true) {
            items.push(i.addClass("frm-editor").attr("frm-index", items.length));
            KeybordHelper.on(i, "enter", onItemKeyEnter);
        }
    });

    this.Submit = function () {
        if (ins.State.enabled === false) {
            return this;
        }
        var ev = jQuery.Event("submiting", {Controller:ins});
        ins.Dom.trigger(ev);
        return this;
    };

    this.on("LCfocus", onFormFocus);
    this.on("disposed", onFormDispose);
    this.constructor = LiberUI.Form;
    return ins;
}
LiberUI.Form.prototype = LController.prototype;
//#endregion

//#region 自动动态弹出面板
LiberUI.PopPanel = function ($elm) {
    var ins = this;
    var popFor = null;
    var mchecker = null;
    var flag = 0;
    LController.call(this, $elm);
    this.option("AutoPopout", true)
        .option("ShowWay", PopPaneBase.ShowWay)
        .option("HideWay", PopPaneBase.HideWay);


    var _checkMouseElm = function () {
        var elm = LiberUI.TryGetHotElement();
        if (elm!= null && (elm[0] == ins.Dom[0] || elm.parents('#' + ins.Dom.ID()).length > 0 || elm[0] == popFor[0] || elm.parents('#' + popFor.ID()).length > 0)) 
        {
            flag = 0;
            mchecker = setTimeout(_checkMouseElm, 500);
        }
        else if(flag>1){
            //如果检测到鼠标移动到其他区域，延迟再检查2次来确定是否隐藏
            ins.hide();
            window.clearTimeout(mchecker);
            mchecker = null;
            flag = 0;

        }
        else {
            flag += 1;
            mchecker = setTimeout(_checkMouseElm, 300);
        }
    };
    var onShow = function (ev) {
        if (PopPaneBase.Actived) {
            PopPaneBase.Actived.hide();
        }
        PopPaneBase.Actived = ins;
        popFor.on("blur", blurView)
              .on("mouseleave", leaveView);
        popFor.off("mouseenter", enterView)
              .off("click", clickView)
              .off("focus", focusView);
        ins.Dom.on("mouseleave", leaveElm);
        _checkMouseElm();
        ins.option("ShowWay").call(ins,ins.Dom);
    };
    var onHide = function (ev) {
      popFor.on("mouseenter", enterView)
            .on("click", clickView)
            .on("focus", focusView);
      popFor.off("blur", blurView)
            .off('mouseleave', leaveView);
      ins.Dom.off("mouseleave", leaveElm);
      ins.option("HideWay").call(ins,ins.Dom);
    };
    var enterView = function (ev) {
        if (ins.option("AutoPopout") === true) {
            ins.show();
        }
    };
    var clickView = function (ev) {
        if (ins.option("AutoPopout") === true) {
            ins.show();
        }
    };
    var focusView = function (ev) {
        if (ins.option("AutoPopout") === true) {
            ins.show();
        }
    };
    var blurView = function (ev) {
        _checkMouseElm();
    };
    var leaveElm = function (ev) {
        _checkMouseElm();
    };
    var leaveView = function (ev) {
        _checkMouseElm();
    };

    this.PopFor = function ($view) {
        $view = $($view).eq(0);
        if (ObjHelper.IsElement($view)) {
            popFor = $view;
            popFor.on("mouseenter", enterView)
                  .on("click", clickView)
                  .on("focus", focusView);
            return ins;
        }
        else{
            return popFor;
        }
    };

    this.on("hiden", onHide);
    this.on("shown", onShow);
    ins.constructor = LiberUI.PopPanel;
    return ins;
};
LiberUI.PopPanel.prototype = LController.prototype;
var PopPaneBase = {
    'ShowWay': function ($elm) {
        var v = this.PopFor();
        var pos = v.offset();
        pos.top = pos.top + v.height()-2;
        var style = {
            display:'block',
            position: 'absolute',
            zIndex: 999,
            width: v.outerWidth()
        }    
        $elm.css(style).appendTo(v.parent()).offset({ left: pos.left, top: pos.top });
        v.addClass("active");
    },
    'HideWay': function ($elm) {
        var v = this.PopFor();
        $elm.hide().appendTo("body");
        v.removeClass("active");
    },
    'Actived':null
}
//#endregion

//#region 文件上传
LiberUI.Uploader = function ($elm) {
    var ins = this;
    LController.call(this, $elm);
    var fileItems = [];
    this.option("FileAPI", "/File/FileAPI")
        .option("UploadNow", true)  //实时上传，or等待用户点击提交
        .option("Multiple", true)  //允许多选
        .option("Thumbnail", true)  //对于图片，是否加载缩略图
        .option("FileType", "")  //允许的文件类型
        .option("MaxSize", 100000000)  //最大文件长度100m
        .option("BlockSize", 51200)  //分块大小，默认50k
        .option("MinSize", 1024);   //最小文件长度1k

    var _input = null;
    if (this.option("Multiple") == true) {
        _input = $("<input type=file multiple='multiple'>");
    }
    else {
        _input = $("<input type=file>");
    }
    
    var onClick = function (ev) {
        _input.trigger("click");
    };

    //TODO:将筛选直接设为input的accept属性

    var onUpdate = function (ev) {
        _input.attr("accept", ins.option("FileType"));
    };

    var onSlcted = function (ev) {
        if (this.files.length == 0) {
            return;
        }
        for (var i = 0; i < this.files.length; i++) {
            var f = this.files[i];
            var itm=fileItems.findObj("name", f.name);
            if (itm != null) {
                //检查是否存在同名文件
            }
            else {
                itm = {
                    name: f.name,
                    uploader: ins,
                    obj: f,
                    process: 0,
                    total: f.size,
                    completed: -1,
                    thumbnail: "",
                    token: "",
                    err:"",
                    Change:LiberUI.UploaderBase.onChange
                };
                fileItems.push(itm);       
            }
            itm.Change("itemSlcted");
            if (f.type.match("image") && ins.option("Thumbnail") == true) {
                //开启了图片预览
                if (window.File && window.FileReader && window.FileList && window.Blob) {
                    var reader = new FileReader();
                    reader.onload = LiberUI.UploaderBase.onImageThumbnailLoad;
                    reader.item = itm;
                    reader.readAsDataURL(f);
                }
                else {
                    //如果不支持，另外处理
                    log("浏览器不支持Html5文件API");
                    break;
                }
            }
            else {
                LiberUI.UploaderBase.checkInfo(itm);
            }
        }
    };

    var onItemChange = function (ev)
    {
        switch (ev.Status) {
            case "checkInfoEnd":
                if (ins.option("UploadNow") == true) {
                    ev.Item.Change("uploadBegin");
                    LiberUI.UploaderBase.uploadItemH5(ev.Item);
                }
                break;
        }
    };

    _input.on("change", onSlcted);

    this.on("update", onUpdate);
    this.on("LCclick", onClick);
    this.on("change", onItemChange);
    this.constructor = LiberUI.Uploader;
}
LiberUI.Uploader.prototype = LController.prototype;
LiberUI.UploaderBase = {
    Filter: function (_types) {

    },
    onChange:function(ev){
        var nev = jQuery.Event("change", { Controller: this.uploader, Item: this, Status: ev });
        this.uploader.Dom.trigger(nev);
    },
    onImageThumbnailLoad:function(ev){
        this.item.thumbnail = this.result;
        this.onload = LiberUI.UploaderBase.onItemLoad;
        this.item.Change("imageLoaded");
        LiberUI.UploaderBase.checkInfo(this.item);
        this.item = null;
    },
    onItemLoad: function (ev) {
        /// <summary>
        /// 读取成功完成
        /// </summary>
        /// <param name="ev" type="type"></param>
        this._item.Change("fileLoad");
        if (this._item.uploader.option("UploadNow") == true) {
            //开启了自动上传
            LiberUI.UploaderBase.uploadItemH5(this._item);
        }
        return this;
    },
    onItemLoadEnd: function (ev) {
        /// <summary>
        /// 读取结束（可能失败，也可能成功）
        /// </summary>
        /// <param name="ev" type="type"></param>
        this._item.Change("fileLoadEnd");
        return this;
    },
    onItemLoading: function (ev) {
        /// <summary>
        /// 读取过程中
        /// </summary>
        /// <param name="ev" type="type"></param>
        this._item.Change("fileLoading");
        return this;
    },
    checkInfo:function(itm){
        var f = itm.obj;
        var md5Token = "";
        var url = itm.uploader.option("FileAPI") + "?mode=getInfo&fileName=" + encodeURI(f.name);
        
        //计算sha1token作为唯一标识
        if (f.size > 2048) {
            try{
                var head = new Uint16Array(f.slice(0, 1024));
                var tail = new Uint16Array(f.slice(f.size - 1025, 1024));
                md5Token = (head.toString() + tail.toString() + f.size.toString()).MD5();
            }
            catch(ex){
                md5Token=encodeURI(f.name).MD5();
            }
        }
        else {
            var body = new Uint16Array(f);
            md5Token = (body.toString() + f.size.toString()).MD5();
        }
        itm.token = md5Token;
        url += "&token=" + itm.token;
        itm.Change("checkInfo");
        var checker = new XMLHttpRequest();
        checker.open("get", url);
        checker.onreadystatechange = LiberUI.UploaderBase.onCheckInfoEnd;
        checker.send();
        checker.item = itm;
    },
    onCheckInfoEnd: function (ev) {
        /// <summary>
        /// 检查服务端是否存在指定文件或片段
        /// </summary>
        /// <param name="ev" type="type"></param>
        if (this.readyState == 4 && this.response) {
            this.onreadystatechange = null;
            var rtn = this.response.toJSON();
            if (rtn.IsPositive) {
                if (rtn.Data.completed < rtn.Data.length) {
                    //获取到已经上传的进度，准备从已完成的部分开始继续上传
                    this.item.completed = rtn.Data.completed;
                }
                else {
                    //已经传完了
                    this.item.Result = rtn.Data;
                    this.item.completed = rtn.Data.completed;
                }
            }
            else {
                //没有查到进度，从头开始传
                this.item.completed = 0;
            }
            this.item.Change("checkInfoEnd");
        }
    },
    uploadItemH5: function (itm) {
        if (itm.obj.size > itm.uploader.option("MaxSize")) {
            itm.Result = { IsPositive: false, ErrorSrc: "LiberUI_Uploader", ErrorCode: "TooLarge" };
            itm.Change("uploadFailure");
            return;
        }
        if (itm.total <= itm.completed) {
            //已经传完了
            itm.Change("uploadEnd");
        } 
        if (itm.obj.size > 4000000 || itm.completed != 0) {
            //大于4m的，分段读取，分段上传
            var url = itm.uploader.option("FileAPI") + "?mode=append&fileName=" + encodeURI(itm.obj.name);
            url += "&token=" + itm.token;
            handler = new XMLHttpRequest();
            handler.item = itm;
            handler.onreadystatechange = LiberUI.UploaderBase.appendEnd;
            
            var fd = new FormData();
            var ln = Math.min(51200, itm.total - itm.completed);//最大50k一次
            var data = itm.obj.slice(itm.completed, itm.completed + ln);  //自上次完成位置读取分段数据
            fd.append("file", data);
            handler.open("post", url + "&start=" + itm.completed + "&total=" + itm.total);
            handler.send(fd);
        }
        else if (itm.obj.size > 512000) {
            //大于500k的，流式上传
            reader = new FileReader();
            reader.item = itm;
            reader.onload = LiberUI.UploaderBase.fileReadEnd;
            reader.readAsArrayBuffer(itm.obj);
        }
        else {
            //否则直接以文件方式上传
            var url = itm.uploader.option("FileAPI") + "?mode=upload&fileName=" + encodeURI(itm.obj.name);
            url += "&token=" + itm.token;
            handler = new XMLHttpRequest();
            handler.item = itm;
            handler.onreadystatechange = LiberUI.UploaderBase.appendEnd;

            var fd = new FormData();
            fd.append("file", itm.obj);
            handler.open("post", url + "&start=" + itm.completed + "&total=" + itm.total);
            handler.send(fd);
        }
    },
    appendEnd: function (ev) {
        if (this.readyState == 4 && this.response.length > 0) {
            var rtn = this.response.toJSON();
            if (rtn.IsPositive) {
                var itm = this.item;
                itm.completed = rtn.Data.completed;
                if (itm.completed < this.item.total) {
                    itm.Change("uploadProcessing");
                    var url = itm.uploader.option("FileAPI") + "?mode=append&fileName=" + encodeURI(itm.obj.name);
                    url += "&token=" + itm.token;
                    handler = new XMLHttpRequest();
                    handler.onreadystatechange = LiberUI.UploaderBase.appendEnd;
                    handler.item = itm;

                    var fd = new FormData();
                    var ln = Math.min(51200, itm.total - itm.completed);//最大50k一次
                    var data = itm.obj.slice(itm.completed, itm.completed + ln);  //自上次完成位置读取分段数据
                    fd.append("file", data);
                    handler.open("post", url + "&start=" + itm.completed + "&total=" + itm.total);
                    handler.send(fd);
                }
                else {
                    itm.Result = rtn.Data;
                    itm.Change("uploadEnd");
                }
            }
            else {
                itm.Result = rtn;
                itm.Change("uploadFailure");
            }
        }
    },
    fileReadEnd: function (ev) {
        var itm = this.item;
        var url = itm.uploader.option("FileAPI") + "?mode=upload&fileName=" + encodeURI(itm.obj.name);
        url += "&token=" + itm.token;
        handler = new XMLHttpRequest();
        handler.item = itm;
        handler.upload.item = itm;
        handler.upload.onprogress = LiberUI.UploaderBase.fileUploading;
        handler.onreadystatechange = LiberUI.UploaderBase.fileUploadEnd;
        handler.open("post", url);
        handler.send(reader.result);
    },
    fileUploading: function (ev) {
        var itm = this.item;
        itm.completed += ev.loaded;
        itm.Change("uploadProcessing");
    },
    fileUploadEnd: function (ev) {
        if (this.readyState == 4 && this.response.length > 0) {
            var rtn = this.response.toJSON();
            var itm = this.item;
            if (rtn.IsPositive) {
                itm.Result = rtn.Data;
                itm.Change("uploadEnd");
            }
            else {
                itm.Result = rtn;
                itm.Change("uploadFailure");
            }
            this.item = null;
            this.upload.item = null;
        }
    }
}
//#endregion

//#region 提示框
LiberUI.Prompt = function ($elm) {
    var ins = this;
    var closer = null;
    //var mask = null;
    LController.call(this, $elm);

    this.option("Delay", 3);

    var onUpdate = function () {
        var dly=ins.option("Delay");
        if(!dly){
            dly=3;
        }
        closer = setTimeout(function () { ins.Dom.removeClass("prompt_active").addClass("prompt_dispose"); setTimeout(function () { ins.dispose(); }, 1000) }, (dly - 1) * 1000);
    };

    var onShow = function () {
        ins.Dom.appendTo("body");
        LayoutHelper.Layout2Wnd(ins.Dom, "AllCenter", null);
        ins.Dom.addClass("prompt_active");
    };

    var onDispose = function () {
        clearTimeout(closer);
        ins.Dom.remove();
        //$("body").unmask();
        //mask.remove();
    };

    this.on("shown", onShow);
    this.on("disposed", onDispose);
    this.on("update", onUpdate);
    this.constructor = LiberUI.Prompt;
}
LiberUI.Prompt.prototype = LController.prototype;
//#endregion

//#region 对话框
LiberUI.Dialoger = function ($elm) {
    /// <summary>
    /// 对话框基础组件
    /// </summary>
    /// <param name="$elm" type="type"></param>
    /// <returns type="LiberUI.Dialoger"></returns>
    var ins = this;
    var btns = [];

    LController.call(this, $elm);
    this.Dom.appendTo("body").hide();

    this.option("MainStyle","Normal")  //基础样式，取决于对话框的用途性质（Warning危险性操作，Normal一般性操作，Info信息告知）
        .option("Mode", "Box");  //"Flat"为扁平化模式,"Box"为默认模式
    this.Dom.addClass("Dialoger");

    var headElm = $("<div class='dlg_head'><h4></h4><i class='dlg_closer'></i></div>").appendTo(ins.Dom);
    var bodyElm = $("<div class='dlg_body'>").appendTo(ins.Dom);
    var bottomElm = $("<div class='dlg_bottom'>").appendTo(ins.Dom).addClass("dlg_bottom");

    var _onKbEnter = function (ev) {
        if (btns[0].fn && ins.State.enabled == true) {
            btns[0].fn();
        }
    };
    var _onKbEsc = function (ev) {
        if (btns.length > 0 && btns[1].fn && ins.State.enabled == true) {
            btns[1].fn();
        }
        else {
            _onHide();
        }
    };
    var _update = function () {
        //ins.Dom.appendTo(tmp);
        if (ins.option("Mode") == "Flat") {
            ins.Dom.addClass("Flat");
        }
        else {
            ins.Dom.removeClass("Flat");
        }
        ins.Dom.addClass(ins.option("MainStyle"));
        bottomElm.children(".dlg_btn").remove();
        for (var i = 0; i < btns.length; i++) {
            var nb = $("<div class='dlg_btn'>").vl(btns[i].title).attr("btnIndex", i);
            nb.appendTo(bottomElm);
            nb.addClass(btns[i].class);
            if (btns[i].icon) {
                nb.prepend($("<i class='soicon'>").addClass(btns[i].icon));
            }
        }

    };
    var _onBtn = function (ev) {
        if (ins.State.enabled == false) {
            return;
        }
        var btn = $(this);
        if (!btn.hasClass("dlg_btn")) {
            btn = btn.parent(".dlg_btn");
            if (btn.length == 0) {
                return;
            }
        }
        var b = parseInt(btn.attr("btnIndex"));
        if (btns[b] && btns[b].fn) {
            btns[b].fn();
        }
    };
    var _onWheel = function (ev) {
        if (ev) {
            ev.stopPropagation();
            ev.preventDefault();
        }
    };
    var _onShow = function () {
        $('html').mask(ins.Dom.show()).addClass("DialogMask");
        if (bodyElm.children().width()) {
            ins.Dom.width(bodyElm.children().outerWidth()+20);
        }
        //TODO:确定body的高度，如果内容超过最大高度，则就是最大高度，否则为内容的高度
        KeybordHelper.globalOn("enter", _onKbEnter);
        KeybordHelper.globalOn("esc", _onKbEsc);
        ins.Dom.addClass("fladeInUp");
    };
    var _onHide = function () {
        ins.Dom.hide().appendTo("body");
        ins.Dom.removeClass("fladeInUp");
        KeybordHelper.globalOff("enter", _onKbEnter);
        KeybordHelper.globalOff("esc", _onKbEsc);
        $('html').unmask();
    };
    var _closeDlg = function (ev) {
        if (ev && ev.stopPropagation) {
            ev.stopPropagation();
        }
        ins.hide();
    };
    var _onDispose = function () {
        $('html').unmask();
        ins.off("shown", _onShow);
        ins.off("hiden", _onHide);
        ins.off("update", _update);
        ins.off("mousewheel", _onWheel);
        ins.off("dispose", _onDispose);
        headElm.undelegate(".dlg_closer", "click", _closeDlg);
        bottomElm.undelegate(".dlg_btn", "click", _onBtn);
        KeybordHelper.globalOff("enter", _onKbEnter);
        KeybordHelper.globalOff("esc", _onKbEsc);
        btns = [];
    };

    this.Title = function (titl) {
        headElm.children('h4').vl(titl.toString());
        return this;
    };
    this.Content = function (cnt) {
        if (ObjHelper.IsElement(cnt)) {
            bodyElm.vl('');
            bodyElm.append(cnt);
        }
        else {
            bodyElm.vl(cnt);
        }
        return this;
    };

    this.BtnEnter = function (btnTitle, btnIcon, btnCallback) {
        if (!btnCallback) {
            btnCallback = _closeDlg;
        }
        btns.splice(0, 0, { title: btnTitle, icon: btnIcon, class: 'btnEnter', fn: btnCallback, index: 0 });
        return this;
    };
    this.BtnEsc = function (btnTitle, btnIcon, btnCallback) {
        if (!btnCallback) {
            btnCallback = _closeDlg;
        }
        if (btns.length > 0) {
            btns.splice(1, 0, { title: btnTitle, icon: btnIcon, fn: btnCallback, index: 1 });
        }
        else {
            btns.splice(0, 0, { title: btnTitle, icon: btnIcon, fn: btnCallback,index:0 });
        }
        return this;
    };
    this.BtnOther = function (btnTitle, btnIcon, btnCallback) {
        btns.splice(btns.length, 0, { title: btnTitle, icon: btnIcon, fn: btnCallback, index: btns.length });
        return this;
    };
    this.RemoveBtn = function (btnIndex) {
        if ($.isNumeric(btnIndex)) {
            btns.slice(btnIndex, 1);
        }
        else {
            btns = [];
        }
        return this;
    };

    this.on("shown", _onShow);
    this.on("hiden", _onHide);
    this.on("update", _update);
    
    bodyElm.on("mousewheel", _onWheel);
    this.on("disposed", _onDispose);
    headElm.delegate(".dlg_closer", "click", _closeDlg);
    bottomElm.delegate(".dlg_btn", "click", _onBtn);
    ins.constructor = LiberUI.Dialoger;
    return ins;
};
LiberUI.Dialoger.prototype = LController.prototype;
//#endregion

//#region 列表
LiberUI.Lister = function ($elm) {
    /// <summary>
    /// 通用列表组件
    /// </summary>
    /// <param name="$elm" type="type"></param>
    /// <returns type="LiberUI.Lister">通用列表组件实例</returns>
    var ins = this;
    var slctedObj = null;

    LController.call(this, $elm);
    this.option("TreeMode", false)
        .option("Slctble", true)
        .option("MultiSlctble",false)
        .option("SlctedStyle", "slcted")
        .option("NodePrefix", "treeSpaner")
        .option("TreeLine", false)
        .option("PrimaryKey", "idstr")
        .option("ParentKey", "parentidstr");
    var tmp = $("<div>").hide().appendTo("body");
    var empty = $("<div class='empty'><i></i>暂无数据</div>");
    var _renderContent = function ($cnt, obj) {
        $cnt.vl(obj["name"]);
    };
    var _onShown = function () {
        var lis = $(tmp).children(".ListItem").appendTo(ins.Dom);
        if (ins.Dom.children(".ListItem").length == 0) {
            empty.appendTo(ins.Dom);
        }
        else {
            empty.appendTo(tmp);
        }
        if (ins.option("TreeMode") == true) {
            ins.Dom.find(".ListItem").each(function (ev) {
                var pbody = $(this).parents(".ListItem").eq(0).children(".li-body");
                if (pbody.length > 0) {
                    var c = $(this).find(".li-content").children().eq(0);
                    var p = pbody.children(".li-content").children().eq(0);
                    if (p.length == 0) {
                        p = pbody.children(".li-content").eq(0);
                    }
                    var pp = parseInt(p.css("paddingLeft"));
                    if (isNaN(pp)) {
                        pp = 0;
                    }
                    if (c.length == 0) {
                        c = $(this).find(".li-content").eq(0);
                    }
                    c.css("paddingLeft", (pp + 32) + "px");
                }
            });
        }
    };
    var _onUpdate = function () {
        slctedObj = null;
        var data = ins.vl();
        var pk = ins.option("PrimaryKey");
        var parentk = ins.option("ParentKey");
        var cntRender = ins.option("ContentRender") || _renderContent;
        var treeMode = ins.option("TreeMode") || true;
        var nodePrefix = ins.option("NodePrefix");
        $(tmp).children(".ListItem").remove();
        ins.Dom.children().remove();
        if (!data) {
            _onShown();
            return;
        }
        else if (Array.isArray(data)) {         
            for (var i = 0; i < data.length; i++) {
                var o = data[i];
                o.$ListItem = $("<div class='ListItem'>");
                o.$Children = null;
                o.$BodyItem = $("<div class='li-body'>").appendTo(o.$ListItem);
                o.$ItemIndent = $("<div class='li-line'>").appendTo(o.$BodyItem);
                o.$ItemPrefix = $("<div class='li-prefix'>").appendTo(o.$BodyItem).addClass(nodePrefix);
                o.$ItemContent = $("<div class='li-content row'>").appendTo(o.$BodyItem);
                cntRender(o.$ItemContent, o);
                o.$ListItem.attr("obj", i);
                o.$BodyItem.attr("obj", i);

                //TODO:检查父级属性已决定将当前节点放在哪
                if (!treeMode || !o[parentk]||o[parentk] === '-1') {
                    o.$ListItem.appendTo(tmp);
                }
                else {
                    var p = data.findObj(pk, o[parentk]);
                    if (p == null) {
                        o.$ListItem.appendTo(tmp);
                    }
                    else {
                        if (p.$Children == null) {
                            p.$Children = $("<div class='li-children'>").appendTo(p.$ListItem);
                        }
                        o.$ListItem.appendTo(p.$Children);
                    }
                }
            }
        }
        else {
            if (empty) {
                empty.appendTo(ins.Dom);
            }
        }
        _onShown();
        
    }
    var onItemClick = function (ev) {
        if (ev & ev.stopPropagation) {
            ev.stopPropagation();
            ev.preventDefault();
        }
        if (ins.option("Slctble") == true) {
            var li = $(this);
            var obj = parseInt(li.attr("obj"));
            var styl = ins.option("SlctedStyle");
            if (ins.option("MultiSlctble") == false) {
                ins.Dom.find(".li-body").removeClass(styl);
            }
            li.toggleClass(styl);
            slctedObj = ins.vl()[obj];
            ins.Dom.trigger("itemSlcted", ins.vl()[obj]);
        }
        else {
            var li = $(this);
            var obj = parseInt(li.attr("obj"));
            ins.Dom.trigger("itemClick", ins.vl()[obj]);
        }

    }

    this.Loading = function ($elm) {
        if (empty) {
            empty.appendTo(tmp);
        }
        if (ObjHelper.IsElement($elm)) {
            ins.Dom.append($elm);
        }
        else if ($elm) {
            var ld = $("<div class='loading'>").vl("<i></i>"+$elm.toString());
            ins.Dom.append(ld);
        }
        else {
            var ld = $("<div class='loading'>").vl("<i></i>正在加载...");
            ins.Dom.append(ld);
        }
        return ins;
    },
    this.Empty = function ($empty) {
        if (ObjHelper.IsElement($empty)) {
            empty = $empty;
        }
        else if ($empty) {
            empty = $("<div class='empty'></div>").vl("<i></i>" + $empty);
        }
        else {
            empty = $("<div class='empty'></div>").vl("<i></i>暂无数据");
        }
        return ins;
    },
    this.UpdateItem = function (obj) {
        if (obj.$ListItem) {
            var i =parseInt(obj.$ListItem.attr("obj"));
            if ($.isNumeric(i)&& i > -1 && i < ins.vl().length) {
                ins.vl()[i] = obj;
            }
            obj.$ItemContent.children().remove();
            ins.option("ContentRender")(obj.$ItemContent,obj);
        }
        _onShown();
    },
    this.AppendItem = function (o) {
        var data = ins.vl();
        data.push(o);
        var i = data.length - 1;
        var pk = ins.option("PrimaryKey");
        var parentk = ins.option("ParentKey");
        var cntRender = ins.option("ContentRender") || _renderContent;
        var treeMode = ins.option("TreeMode") || true;
        var nodePrefix = ins.option("NodePrefix");

        o.$ListItem = $("<div class='ListItem'>");
        o.$Children = null;
        o.$BodyItem = $("<div class='li-body'>").appendTo(o.$ListItem);
        o.$ItemIndent = $("<div class='li-line'>").appendTo(o.$BodyItem);
        o.$ItemPrefix = $("<div class='li-prefix'>").appendTo(o.$BodyItem).addClass(nodePrefix);
        o.$ItemContent = $("<div class='li-content row'>").appendTo(o.$BodyItem);
        cntRender(o.$ItemContent, o);
        o.$ListItem.attr("obj", i);
        o.$BodyItem.attr("obj", i);

        //TODO:检查父级属性决定将当前节点放在哪
        if (!treeMode || o[parentk] === '-1') {
            o.$ListItem.appendTo(ins.Dom);
        }
        else {
            var p = data.findObj(pk, o[parentk]);
            if (p == null) {
                o.$ListItem.appendTo(ins.Dom);
            }
            else {
                if (p.$Children == null) {
                    p.$Children = $("<div class='li-children'>").appendTo(p.$ListItem);
                }
                o.$ListItem.appendTo(p.$Children);
            }
        }
        _onShown();
    },
    this.RemoveItem = function (obj) {
        if (obj.$ListItem) {
            var i = parseInt(obj.$ListItem.attr("obj"));
            ins.vl().removeOn(i);
            //更新后继所有列表项的索引
            obj.$ListItem.remove();
            ins.Dom.find(".List-Item").each(function (li) {
                var oi = parseInt(li.attr("obj"));
                if (oi > i) {
                    li.attr("obj", oi - 1);
                }
            })
        }
    }
    this.Slct = function (index) {
        /// <summary>
        /// 选中列表中指定的项，或者获取列表中当前已选择的数据项
        /// </summary>
        /// <param name="index" type="type"></param>
        /// <returns type=""></returns>
        if (!index) {
            return slctedObj;
        }
        else {
            if (index > -1 && index < ins.vl().length) {
                slctedObj = ins.vl()[index];
            }
        }
    }

    this.on("update", _onUpdate);
    //this.on("shown", _onShown);
    ins.Dom.delegate(".li-body", "click", onItemClick);
    this.constructor = LiberUI.Lister;
    return ins;
}
LiberUI.Lister.prototype = LController.prototype;
//#endregion

//#region 分页
LiberUI.Paging = function ($elm) {
    var ins = this;
    var submitData = null;
    var row = null;
    var total = null;
    var currPage = null;
    var trailerPage = null;//尾页
    var startRow = currPage * row - row + 1;//当前显示条数范围
    var endRow;//结束条数范围
    var ToPage = 1; //目标页
    var dom = {};

    LController.call(this, $elm);
    
    dom.$paging = $("<div class='LiberUI-Paging'>");
    dom.$tip = $("<div style='float:left;'>当前<span class='startRow'>" + 0 + "</span>-<span class='endRow'>" + 0 + "</span>|<span class='total'>共" + 0 + "条</span></div>").appendTo(dom.$paging);
    dom.$count = $("<div class='paging-operate' style='float:right'>");
    dom.$count.append(" <div pid='1' class='homePage button btn-lite'>首页</div>");
    dom.$single = $("<span class='pagination'>");

    dom.$count.append(dom.$single);
    dom.$count.append("<div class='trailerPage button btn-lite'>尾页</div> <input class='toPage' type='number' value='1' min='1' max='" + trailerPage + "'><span class='maxPage'>共" + trailerPage + "页</span><div class='findPage button' >GO</div>");
    dom.$count.appendTo(dom.$paging);
    dom.$paging.appendTo(ins.Dom);

    var _onUpdate = function () {
        total = ins.option("Total") || 0;//总计
        currPage = ins.option("CurrPage") || 1;//当前页
        row = ins.option("Row") || 0;//行数
        submitData = ins.option("BtnClick");//点击按钮回调函数
    
        if ((total % row) != 0) {   //判断尾页页码
                trailerPage = parseInt(total / row) + 1;
                
        } else {
            trailerPage = total / row;
        }

        //dom.$tip.remove();
        dom.$tip.children(".total").vl("共" + total + "条");
        dom.$count.children(".toPage").attr("max", trailerPage).vl(1);
        dom.$count.children(".maxPage").vl(trailerPage);

        createBtn(currPage);
        if ((currPage * row) > total) {
            endRow = total;
        } else {
            endRow = currPage * row;
        }
        dom.$tip.children(".startRow").vl(total==0?0:currPage * row - row + 1);
        dom.$tip.children(".endRow").vl(endRow);
        if (total == 0) {
            ins.Dom.hide();
        }
        else {
            ins.Dom.show();
        }
    };
    var createBtn = function (pid) {
        dom.$single.children().remove();
        pid = parseInt(pid);
        if (pid == 1 || pid == 2 || pid == 3) {
            if (trailerPage >= 5) {
                for (var i = 1; i <= 5; i++) {
                    if (i == pid) {
                        dom.$single.append("<span pid='" + i + "' class='button '>" + i + "</span>");
                    } else
                        dom.$single.append("<span pid='" + i + "' class='button btn-lite'>" + i + "</span>");
                }
            } else {
                for (var i = 1; i <= trailerPage; i++) {
                    if (i == pid) {
                        dom.$single.append("<span pid='" + i + "' class='button '>" + i + "</span>");
                    } else
                        dom.$single.append("<span pid='" + i + "' class='button btn-lite'>" + i + "</span>");
                }
            }
        }
        else if (pid == trailerPage || pid == (trailerPage - 1) || pid == (trailerPage - 2)) {
            var space = 1;
            if (trailerPage - 4 > 0) {
                space = trailerPage - 4;
            }
            for (var i = space; i <= trailerPage; i++) {
                if (i == pid) {
                    dom.$single.append("<span pid='" + i + "' class='button '>" + i + "</span>");
                } else
                    dom.$single.append("<span pid='" + i + "' class='button btn-lite'>" + i + "</span>");
            }
        }
        else {
            for (var i = (pid - 2) ; i <= (pid + 2) ; i++) {
                if (i == pid) {
                    dom.$single.append("<span pid='" + i + "' class='button '>" + i + "</span>");
                } else
                    dom.$single.append("<span pid='" + i + "' class='button btn-lite'>" + i + "</span>");
            }
        }
    };
    var goPage = function (p) {
        if ((p * row) > total) {
            endRow = total;
        } else {
            endRow = p * row;
        }
        dom.$tip.children(".startRow").vl(total == 0 ? 0 : p * row - row + 1);
        dom.$tip.children(".endRow").vl(endRow);
        createBtn(p);
        submitData(p, row);
    };
    var onHomePage = function () {
        var btn = $(this);
        if (btn.hasClass("homePage")) {
            goPage(1);
        }
        else if (btn.hasClass("trailerPage")) {
            goPage(trailerPage);
        }
        else if (btn.hasClass("findPage")) {
            var p = dom.$count.children(".toPage").vl();
            if (p < 1 || p > trailerPage) {
                
            }
            else {
                goPage(p);
            }
        }
        else if (btn.hasClass("btn-lite")) {
            var pid = parseInt(btn.attr("pid"));
            if (pid > 0 && pid <= trailerPage) {
                goPage(pid);
            }
        }
        else { }
    };

    this.on("update", _onUpdate);

    ins.Dom.delegate(".paging-operate>div", "click", onHomePage);//按钮
    ins.Dom.delegate(".pagination>span", "click", onHomePage);//页码
    this.constructor = LiberUI.Paging;
    return ins;
}
LiberUI.Paging.prototype = LController.prototype;
//#endregion

//#region 表格
LiberUI.Table = function ($elm) {
    var ins = this;
    var header = null;
    var body = null;
    var footer = null;
    var rows = [];
    var cols = [];
    LController.call(this, $elm);
    ins.vl([]);
    ins.Dom.addClass("liberui-grid-table");
    header = $("<div class='gridRow head'>").appendTo(ins.Dom);
    body = $("<div class='gridBody'>").appendTo(ins.Dom);

    var _update = function () {
        //判断并重置标题行
        if (header.children().length != cols.length) {
            header.children().remove();
            for (var i = 0; i < cols.length; i++) {
                //构造表头元素
                var h = $("<div class='gridCol'>").css("width", cols[i].Width)
                                                   .vl(cols[i].Title)
                                                   .attr("col-index", i)
                                                   .appendTo(header);
            }
        }

        //重新渲染每个行
        rows = [];
        body.children().remove();
        for (var i = 0; i < ins.vl().length; i++) {
            _renderRow(i);
        }
    }

    var _renderRow = function (i) {
        var obj = ins.vl()[i];
        var r = $("<div class='gridRow'>").appendTo(body);
        for (var i = 0; i < cols.length; i++) {
            //构造行中的列
            var c = $("<div class='gridCol'>").css("width", cols[i].Width)
                                              .addClass(cols[i].ExStyle)
                                              .attr("col-index", i)
                                              .appendTo(r);
            if (cols[i].Render) {
                c.append(cols[i].Render(obj));
            }
            else if (obj.hasOwnProperty(cols[i].Binding)) {
                c.vl(obj[cols[i].Binding]||"&nbsp;");
            }
            else if (ObjHelper.IsElement(cols[i].Binding)) {
                c.vl(cols[i].Binding);
            }
            else {
                c.vl("&nbsp;");
            }
        }
        r.data(obj);
        rows.push(r);
    }

    this.Col = function (title, width, inlineEdit, advEditor,bindProp,render,exstyle) {
        /// <summary>
        /// 添加并设置表格列
        /// </summary>
        /// <param name="title" type="type">列标题</param>
        /// <param name="width" type="type">列宽度（百分比）</param>
        /// <param name="inlineEdit" type="type">是否启用行内编辑模式</param>
        /// <param name="advEditor" type="type">启用高级编辑（在列获得焦点时得到一个回调通知）</param>
        /// <param name="bindProp" type="type">简单绑定（列值绑定到对应数据对象的指定属性上）</param>
        /// <param name="render" type="type">高级绑定（列值通过指定的方法来更新）</param>

        var c = {
            Title: title || "无列名",
            Width: width || "0",
            InlineEditor: inlineEdit ? $("<input>") : null,
            FnOnFocus:ObjHelper.IsFunc(advEditor)?advEditor:null,
            Binding: bindProp||"",
            Render: ObjHelper.IsFunc(render) ? render : null,
            ExStyle: exstyle || ""
        }
        cols.push(c);
        return ins;
    };

    this.Row = function (index,obj) {
        /// <summary>
        /// 添加或获取指定索引的行元素
        /// </summary>
        /// <param name="index" type="type">行索引</param>
        var i = $.parseInt(index);
        if (i >= 0 & i < rows.length) {
            if (!obj) {
                return rows[i];
            }
            else {
                ins.vl().push(obj);
                _renderRow(ins.vl().length - 1);
            }
        }
    };

    this.on("update", _update);
    this.constructor = LiberUI.Table;
    return this;
}
LiberUI.Table.prototype = LController.prototype;
LiberUI.TableRow = {
    
}

//#endregion

//#region MVC视图
LiberUI.View = function ($elm) {
    var ins = this;

    LController.call(this, $elm);
    var tpl = laytp(ins.Dom[0].innerHTML);

    var _onUpdate=function(){
        var d = ins.vl();
        var u = tpl.render(d);
        ins.Dom.innerHTML = u;
    }

    this.on("update", _onUpdate);
    this.constructor = LiberUI.View;
    return this;
}
LiberUI.View.prototype = LController.prototype;
//#endregion

LiberUI.TabPanel = function(domId) {
    if (!domId) {
        console.err('domId is not defined!');
        return;
    }
    this.__dom = $(domId);

    this.__init();
};
LiberUI.TabPanel.prototype = {
    __init: function () {

        $(this.__dom).find('.tab-panel-header .item').on('click', function (e) {
            var tabPanelHeader = $(this).parent()
               , tabPanelBody = tabPanelHeader.next().children();

            //移除所有激活项
            tabPanelHeader.children().removeClass('active');
            tabPanelBody.removeClass('active');

            //激活对应选项
            tabPanelBody.eq($(this).index()).addClass('active');
            $(this).addClass('active');

        });
    }
};
